#include "FKLogger.h"
#include "FKManagerType.h"
#include "FKWidgetNames.h"

#include "FKApplication.h"
//#include "FKGLWidget.h"
#include "FKWorldReferent.h"
#include <QTimer>
#include "FKEventNames.h"
#include "FKClient.h"
#include "FKEvent.h"
#include "FKUser.h"
#include "FKRoom.h"
#include "FKFilesList.h"
#include "FKFileInfo.h"
#include "FKMenuInterface.h"
#include "FKRoomInterface.h"
#include "FKVisualInterfaceView.h"
#include "FKDisplayReferent.h"

#include "FKUserInterface.h"

FKUserInterface::FKUserInterface(QObject *parent):QObject(parent){
    FK_CBEGIN
    _client=0;
    _room=0;
    _menu=0;
    _world=0;
    _roomInterface=0;
    FK_CEND
}

FKUserInterface::~FKUserInterface(){
    FK_DBEGIN
    FK_DEND
}

void FKUserInterface::setMenuInterface(FKMenuInterface* menu){
    if(!_menu){
        if(!menu)menu=new FKMenuInterface(this);
        _menu=menu;
    }
}

void FKUserInterface::setAvaliableRoomTypes(const QList<FKRoomModule*> &lst){
    _roomTypes.clear();
    foreach(FKRoomModule* r, lst)_roomTypes.insert(r->roomType(),r->roomClass());
    if(_menu)_menu->setAvaliableRoomTypes(_roomTypes.keys());
}

void FKUserInterface::show(){
//    _menu->showFullScreen();
}

void FKUserInterface::start(){
//    installGLWidget();
    installMenuInterface();
}

void FKUserInterface::installMenuInterface(){
    static bool need=true;
    if(need){
        _menu->initialize(0);
        for(QMap<QString,QString>::ConstIterator lng=fkApp->langs().constBegin();lng!=fkApp->langs().constEnd();++lng){
            _menu->addLang(lng.key(),lng.value());
        }
        //_menu->showFullScreen();
        _menu->show();
        _menu->toLangMenu();

        connect(_menu,SIGNAL(createUserRequested(QString)),SLOT(genUser(QString)));
        connect(_menu,SIGNAL(deleteUserRequested(QString)),SLOT(degenUser(QString)));
        connect(_menu,SIGNAL(addUserRequested(QString)),SLOT(chooseUser(QString)));
        connect(_menu,SIGNAL(removeUserRequested(QString)),SLOT(releaseUser(QString)));
        connect(_menu,SIGNAL(managerRequested(QString,QString,int)),SIGNAL(managerRequested(QString,QString,int)));
        connect(_menu,SIGNAL(usersApply()),SLOT(submitUsers()));
        connect(_menu,SIGNAL(enterRoomRequested(qint32)),SLOT(enterRoomRequested(qint32)));
        connect(_menu,SIGNAL(createRoomRequested(QString,QString,QString,QString)),SLOT(createRoomRequested(QString,QString,QString,QString)));
        connect(_menu,SIGNAL(updateRoomList()),SLOT(roomListUpdateRequested()));
        connect(_menu,SIGNAL(chooseClientRequested(QString,QString)),SIGNAL(clientRequested(QString,QString)));
        connect(_menu,SIGNAL(genClientRequested(QString,QString,QVariant)),SIGNAL(genClient(QString,QString)));
//        connect(_mstructure,SIGNAL(messageRequesed(QString)),SLOT(messageRequested(QString)));

//        connect(_mstructure,SIGNAL(skipAppFilesUpdate()),SLOT(fromUpdateMenu()));
//        connect(_mstructure,SIGNAL(skipAppFilesUpdate()),SLOT(toUserMenu()));
        connect(_menu,SIGNAL(appFilesReplace(QStringList,QList<quint8>)),SIGNAL(appFilesReplaceRequested(QStringList,QList<quint8>)));
        connect(_menu,SIGNAL(appFileUpdate(QString,quint8)),SIGNAL(appFileUpdateRequested(QString,quint8)));
        connect(_menu,SIGNAL(downloadInterruptionRequested()),SIGNAL(stopAppFilesDLRequested()));
//        connect(_mstructure,SIGNAL(exitAppFilesDLRequested()),SLOT(fromUpdateMenu()));
//        connect(_mstructure,SIGNAL(exitAppFilesDLRequested()),SLOT(managerResetRequested()));

        need=false;
    }
}

void FKUserInterface::managerResetRequested(){
    emit managerRequested(FKManagerType::none,QString(),0);
}

FKUser* FKUserInterface::activeUser(){
    if(_client){
        return _client->users().at(0);
    }else{
        return 0;
    }
}

FKRoom* FKUserInterface::activeRoom(){
    return _room;
}

void FKUserInterface::enterRoomRequested(qint32 roomID){
    if(_client){
        qint32 id=_client->getID();
        qint32 idu=_client->users().at(0)->getID();
        emit newAction(FKEvent::makeAction(idu,FKEventName::a_enterRoom,roomID,id,idu,idu));
    }
}

void FKUserInterface::createRoomRequested(QString roomType, QString roomName, QString description, QString password){
    if(_client){
        qint32 id=_client->getID();
        qint32 idu=_client->users().at(0)->getID();
        QStringList sl;
        sl<<_roomTypes.value(roomType)<<roomName<<description<<password;
        emit newAction(FKEvent::makeAction(idu,FKEventName::a_createRoom,sl,id,idu,idu));
    }
}

void FKUserInterface::managerCreated(QString managerType){
//    fromMainMenu();
    if(managerType==FKManagerType::host || managerType==FKManagerType::client){
        _menu->fromMainMenu();
        _menu->toClientMenu();
    }else if(managerType==FKManagerType::single){
        _menu->fromMainMenu();
        emit clientRequested(FKPaths::localClient,FKPaths::localClientPassword);
    }else{
        FK_MLOG("Unknown manager type created")
    }
}

void FKUserInterface::managerReseted(){
//    _mstructure->setDisconnected();
//    emit stopAppFilesDLRequested();
//    fromUpdateMenu();
//    fromRoom();
    roomChosen(0);
    _client=0;
    _menu->fromAppUpdateMenu();
    _menu->fromRoomList();
    _menu->fromUserMenu();
    _menu->fromClientMenu();
    _menu->toMainMenu();
}

void FKUserInterface::managerCreationFalied(){
    message(QString(tr("Failed create object manager")));
//    _mstructure->setDisconnected();
}

void FKUserInterface::setClient(FKClient *client){
    emit newAction(FKEvent::makeAction(client->getID(),FKEventName::a_avaliableRoomTypes,QVariant(_roomTypes.values()),client->getID(),client->getID(),client->getID()));
    _menu->fromClientMenu();
    _client=client;
    connect(client,SIGNAL(systemMessage(QString)),SLOT(message(QString)));
//    connect(client,SIGNAL(addUser()),SLOT(addUser()));
    connect(client,SIGNAL(userListChanged(QStringList)),_menu,SLOT(refreshClientAvaliableUsers(QStringList)));
    connect(client,SIGNAL(currentUserListChanged(QStringList)),_menu,SLOT(refreshClientCurrentUsers(QStringList)));
    connect(client,SIGNAL(refreshRoomList(QList<QMap<int,QVariant> >)),_menu,SLOT(setRoomList(QList<QMap<int,QVariant> >)));
    connect(client,SIGNAL(submitUsers()),SLOT(submitUsers()));
    FKEvent* e=FKEvent::makeAction(_client->getID(),FKEventName::a_addUserToList,QString(),_client->getID(),_client->getID(),_client->getID());
    emit newAction(e);
    FKFilesList server=client->serverFiles().value<FKFilesList>();
    FKFilesList local(fkApp->appVersion());
    if(local.filter(FKOSType::curOS)>=server.filter(FKOSType::curOS)){
        _menu->toUserMenu();
    }else{
        _menu->fromClientMenu();
        setUpdateFilesList(server, local);
        _menu->toAppUpdateMenu();
    }
}

void FKUserInterface::message(const QString m){
    if(_roomInterface){
        _roomInterface->showMessage(m);
    }else{
        _menu->showMessage(m);
    }
}

void FKUserInterface::setDownloaded(QString file, quint8 osType, qint64 size){
    _menu->setDownloaded(file,osType,size);
}

void FKUserInterface::setDownloadComplete(QString file, quint8 osType, bool success){
    _menu->setDownloadComplete(file,osType,success);
}

void FKUserInterface::genUser(QString userName){
    if(_client){
        FKEvent* e=FKEvent::makeAction(_client->getID(),FKEventName::a_addUserToList,userName,_client->getID(),_client->getID(),_client->getID());
        emit newAction(e);
    }else{
        message(QString(tr("Cannot gen user with no client setted")));
    }
}

void FKUserInterface::degenUser(QString userName){
    if(_client){
        FKEvent* e=FKEvent::makeAction(_client->getID(),FKEventName::a_removeUserFromList,userName,_client->getID(),_client->getID(),_client->getID());
        emit newAction(e);
    }else{
        message(QString(tr("Cannot delete user with no client setted")));
    }
}

//void FKUserInterface::updateUserList(QStringList userList){
//    _mstructure->updateUserList(userList);
//}

//void FKUserInterface::updateUsers(){
//    _mstructure->updateActiveUserList(_client->userNames());
//}

void FKUserInterface::chooseUser(QString userName){
    foreach (QString s, _client->userNames()){
        releaseUser(s);
    }
    qint32 id=_client->getID();
    emit newAction(FKEvent::makeAction(id,FKEventName::a_addUser,userName,id,id,id));
}

void FKUserInterface::releaseUser(QString userName){
    qint32 id=_client->getID();
    emit newAction(FKEvent::makeAction(id,FKEventName::a_removeUser,userName,id,id,id));
}

void FKUserInterface::submitUsers(){
    if(_client->users().count()==1){
        foreach(QObject* obj,_client->users())obj->disconnect(this);
//        fromClientMenu();
        _menu->fromUserMenu();
        roomListUpdateRequested();
        _menu->toRoomList();

        connect(_client->users().at(0),SIGNAL(roomChosen(FKRoom*)),SLOT(roomChosen(FKRoom*)));
        connect(_client->users().at(0),SIGNAL(privateMessageRecieved(QString)),SLOT(privateMessage(QString)));
        connect(_client->users().at(0),SIGNAL(commandMessageRecieved(QString)),SLOT(commandMessage(QString)));
        connect(_client->users().at(0),SIGNAL(chatErrorMessageRecieved(QString)),SLOT(chatErrorMessage(QString)));
    }else{
        message(QString(tr("You must choose user before continue")));
    }
}

FKClient* FKUserInterface::activeClient(){
    return _client;
}

void FKUserInterface::roomChosen(FKRoom *room){
    if(_room==room)return;
    if(_room){
        _room->setActive(false);
        if(_roomInterface){
            _roomInterface->deleteLater();
            _roomInterface=0;
        }
        if(_world){
            _world->deleteLater();
            _world=0;
        }
        disconnect(_room,SIGNAL(gotPublicMessage(QString)),this,SLOT(publicMessage(QString)));
        disconnect(_room,SIGNAL(loadingComplete()),this,SLOT(roomLoadingComplete()));
//        disconnect(_room,SIGNAL(loadingBegan(int,int)),_ls,SLOT(setMax(int,int)));
//        disconnect(_room,SIGNAL(loadingBegan(int,int)),this,SLOT(toLoadScreen()));
//        disconnect(_room,SIGNAL(loadingProgress(int,int)),_ls,SLOT(setVal(int,int)));
//        disconnect(_room,SIGNAL(loadingEnded()),this,SLOT(fromLoadScreen()));
//        disconnect(_room,SIGNAL(loadingEnded()),this,SLOT(toFullScreenRoom()));
//        disconnect(_room,SIGNAL(loadingBegan(int,int)),_gl,SLOT(initScreen()));
//        disconnect(_room->world(),SIGNAL(worldAction(qint32,QString,QVariant,qint32)),this,SLOT(worldAction(qint32,QString,QVariant,qint32)));
//        fromFullScreenRoom();
//        _gl->setWorld(0);
    }
    if(room){
        room->setActive(true);
        _menu->fromRoomList();
        _roomInterface=room->interfaceClass();
        _roomInterface->initialize(_menu->view());
        foreach(QString str,room->messageHistory())_roomInterface->addChatMessage(str);
        connect(_roomInterface,SIGNAL(chatMessageRequested(QString)),SLOT(messageRequested(QString)));
        _world=room->worldClass();
        FKDisplayReferent::setWorldReferent(_world);
        _roomInterface->setActorsModel(room->actorsModel());
        room->connectInterface(_roomInterface);
        connect(_roomInterface,SIGNAL(areaClicked(QPoint)),_world,SLOT(areaClicked(QPoint)));
        connect(_world,SIGNAL(mouseClicked(QPoint,qint32)),_roomInterface,SLOT(mouseClicked(QPoint,qint32)));
//        connect(_world,SIGNAL(sceneLoadingComplete()),SLOT(sceneLoadingComplete()));
        connect(_world,SIGNAL(sceneLoadingComplete()),room,SLOT(sceneLoaded()));
        connect(room,SIGNAL(loadingComplete()),SLOT(roomLoadingComplete()));
        connect(_roomInterface->view(),SIGNAL(resized(QSize)),_world,SLOT(resize(QSize)));
        connect(_roomInterface->view(),SIGNAL(beforeRendering()),_world,SLOT(draw()),Qt::DirectConnection);
        connect(_roomInterface->view(),SIGNAL(beforeRendering()),_world,SLOT(loadSceneCall()),Qt::DirectConnection);
        connect(_roomInterface->view(),SIGNAL(afterRendering()),_roomInterface->view(),SLOT(update()));
        connect(room,SIGNAL(gotPublicMessage(QString)),SLOT(publicMessage(QString)));
        connect(room,SIGNAL(loadSceneRequested()),_world,SLOT(loadSceneRequest()));
        connect(_roomInterface,SIGNAL(quitRoomRequested()),SLOT(roomResetRequested()));
        connect(_roomInterface,SIGNAL(startRoomRequested()),SLOT(startRoomRequested()));
        connect(room,SIGNAL(loadingBegan(int,int)),_roomInterface,SLOT(roomLoadingBegan(int,int)));
        connect(room,SIGNAL(loadingProgress(int,int)),_roomInterface,SLOT(setRoomLoadingProgress(int,int)));
        connect(room,SIGNAL(loadingEnded()),_roomInterface,SLOT(roomStarted()));
        _roomInterface->setActiveUser(activeUser()->getID());
        _roomInterface->show();
        //_roomInterface->showFullScreen();
        connect(_roomInterface,SIGNAL(worldAction(qint32,QString,QVariant,qint32)),this,SLOT(worldAction(qint32,QString,QVariant,qint32)));
//        _gl->setWorld(room->world());
//        _gl->installEventFilter(room->world());
//        room->world()->setActiveUser(activeUser()->getID());
//        fromRoomList();
//        toRoom();
    }else{
        _menu->toRoomList();
    }
    _room=room;
}

void FKUserInterface::worldAction(qint32 object, QString subject, QVariant value, qint32 emitter){
    emit newAction(FKEvent::makeAction(object,subject,value,activeClient()->getID(),activeUser()->getID(),emitter));
}

void FKUserInterface::roomResetRequested(){
    if(_client){
        qint32 id=_client->getID();
        qint32 idu=_client->users().at(0)->getID();
        emit newAction(FKEvent::makeAction(idu,FKEventName::a_exitRoom,QVariant(),id,idu,idu));
    }
}

void FKUserInterface::messageRequested(QString message){
    FKUser* user=activeUser();
    if(user){
        emit newAction(FKEvent::makeAction(user->getID(),FKEventName::a_message,message,_client->getID(),_client->users().at(0)->getID(),_client->users().at(0)->getID()));
    }
}

void FKUserInterface::publicMessage(QString message){
    _roomInterface->addChatMessage(QString("<font color = black><\\font>")+message);
}

void FKUserInterface::privateMessage(QString message){
    _roomInterface->addChatMessage(QString("<font color = green><\\font>")+message);
}

void FKUserInterface::commandMessage(QString message){
    _roomInterface->addChatMessage(QString("<font color = blue><\\font>")+message);
}

void FKUserInterface::chatErrorMessage(QString message){
    _roomInterface->addChatMessage(QString("<font color = red><\\font>")+message);
}

void FKUserInterface::startRoomRequested(){
    emit newAction(FKEvent::makeAction(activeRoom()->getID(),FKEventName::a_beginLoading,QVariant(),_client->getID(),activeUser()->getID(),activeUser()->getID()));
}

void FKUserInterface::roomListUpdateRequested(){
    qint32 id=_client->getID();
    emit newAction(FKEvent::makeAction(id,FKEventName::a_updateRoomList,QString(),id,id,id));
}

//void FKUserInterface::roomListUpdated(QMap<qint32, QString> roomList){
//    Q_UNUSED(roomList)
//}

void FKUserInterface::setUpdateFilesList(FKFilesList &server, FKFilesList &local){
    FKFilesList::diff(server,local);
    FKFilesList::compare(server,local);
    _menu->setUpdateFilesList(server.names(),server.osTypes(),server.versions(),server.weights(),local.versions(),local.weights());
}

//FKWorldReferent* FKUserInterface::createWorld(const QString &className) const{
//    const QMetaObject* m=_worldFactory.value(className,0);
//    if(m){
//        QObject* obj=m->newInstance();
//        FKWorldReferent* w=qobject_cast<FKWorldReferent*>(obj);
//        if(!w){
//            FK_MLOGV("invalid world registered",className)
//            obj->deleteLater();
//            return 0;
//        }
//        return w;
//    }else{
//        FK_MLOGV("try create unregistered world",className)
//        return 0;
//    }
//}

//FKRoomInterface* FKUserInterface::createRoomInterface(const QString &className) const{
//    const QMetaObject* m=_interfaceFactory.value(className,0);
// //    FK_MLOGV("class",m->className())
//    if(m){
//        QObject* obj=m->newInstance();
//        FKRoomInterface* w=qobject_cast<FKRoomInterface*>(obj);
//        if(!w){
//            FK_MLOGV("invalid interface registered",className)
//            obj->deleteLater();
//            return 0;
//        }
//        return w;
//    }else{
//        FK_MLOGV("try create unregistered interface",className)
//        return 0;
//    }
//}

//void FKUserInterface::sceneLoadingComplete(){
    //emit newAction(FKEvent::makeAction(activeRoom()->getID(),FKEventName::A_sceneLoadingComplete,QVariant(),activeClient()->getID(),activeUser()->getID(),activeUser()->getID()));
//}

void FKUserInterface::roomLoadingComplete(){
    emit newAction(FKEvent::makeAction(activeRoom()->getID(),FKEventName::a_clientLoadingComplete,QVariant(),activeClient()->getID(),activeUser()->getID(),activeUser()->getID()));
}
